/**
 * Copyright 2018 jianggujin (www.jianggujin.com).
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jianggujin.modulelink.mvc.converter;

import java.util.HashMap;
import java.util.Map;

import com.jianggujin.modulelink.mvc.converter.JConverters.JBigDecimalConverter;
import com.jianggujin.modulelink.mvc.converter.JConverters.JBigIntegerConverter;
import com.jianggujin.modulelink.mvc.converter.JConverters.JBooleanConverter;
import com.jianggujin.modulelink.mvc.converter.JConverters.JByteArrayConverter;
import com.jianggujin.modulelink.mvc.converter.JConverters.JByteConverter;
import com.jianggujin.modulelink.mvc.converter.JConverters.JDateConverter;
import com.jianggujin.modulelink.mvc.converter.JConverters.JDoubleConverter;
import com.jianggujin.modulelink.mvc.converter.JConverters.JFloatConverter;
import com.jianggujin.modulelink.mvc.converter.JConverters.JIntegerConverter;
import com.jianggujin.modulelink.mvc.converter.JConverters.JLongConverter;
import com.jianggujin.modulelink.mvc.converter.JConverters.JShortConverter;
import com.jianggujin.modulelink.mvc.converter.JConverters.JSqlDateConverter;
import com.jianggujin.modulelink.mvc.converter.JConverters.JTimeConverter;
import com.jianggujin.modulelink.mvc.converter.JConverters.JTimestampConverter;

/**
 * 用于将客户端请求的 String 类型数据转换成指定的数据类型
 * 
 * 可以通过实现 {@link JConverter} 定制自己的类型转换规则:
 * 1：实现 {@link JConverter} 接口
 * 2：注册：{@link #register(Class, JConverter)}
 * 
 * 注意：后注册的 {@link JConverter} 会直接覆盖掉先注册的，因此可以通过覆盖的方式取代默认实现类，达成定制化的需求
 * 
 * @author jianggujin
 *
 */
public class JTypeConverter {

   private final Map<Class<?>, JConverter<?>> converterMap = new HashMap<Class<?>, JConverter<?>>();
   private static JTypeConverter instance = new JTypeConverter();

   private JTypeConverter() {
      register(Integer.class, new JIntegerConverter());
      register(int.class, new JIntegerConverter());
      register(Long.class, new JLongConverter());
      register(long.class, new JLongConverter());
      register(Double.class, new JDoubleConverter());
      register(double.class, new JDoubleConverter());
      register(Float.class, new JFloatConverter());
      register(float.class, new JFloatConverter());
      register(Boolean.class, new JBooleanConverter());
      register(boolean.class, new JBooleanConverter());
      register(java.util.Date.class, new JDateConverter());
      register(java.sql.Date.class, new JSqlDateConverter());
      register(java.sql.Time.class, new JTimeConverter());
      register(java.sql.Timestamp.class, new JTimestampConverter());
      register(java.math.BigDecimal.class, new JBigDecimalConverter());
      register(java.math.BigInteger.class, new JBigIntegerConverter());
      register(byte[].class, new JByteArrayConverter());

      register(Short.class, new JShortConverter());
      register(short.class, new JShortConverter());
      register(Byte.class, new JByteConverter());
      register(byte.class, new JByteConverter());
   }

   /**
    * 获得实例
    * 
    * @return
    */
   public static JTypeConverter getInstance() {
      return instance;
   }

   /**
    * 注册转换器
    * 
    * @param type
    * @param converter
    */
   public <T> void register(Class<T> type, JConverter<T> converter) {
      converterMap.put(type, converter);
   }

   /**
    * 将 String 数据转换为指定的类型
    * 
    * @param type
    *           需要转换成为的数据类型
    * @param s
    *           被转换的 String 类型数据，注意： s 参数不接受 null 值，否则会抛出异常
    * @return 转换成功的数据
    */
   public final Object convert(Class<?> type, String s) throws JConvertException {
      if (String.class.equals(type)) {
         return ("".equals(s) ? null : s); // 用户在表单域中没有输入内容时将提交过来 "",
                                           // 因为没有输入,所以要转成 null.
      }
      s = s.trim();
      if ("".equals(s)) { // 前面的 String跳过以后,所有的空字符串全都转成 null, 这是合理的
         return null;
      }
      // 以上两种情况无需转换,直接返回, 注意, 本方法不接受null为 s 参数(经测试永远不可能传来null, 因为无输入传来的也是"")
      // String.class提前处理

      // --------
      JConverter<?> converter = converterMap.get(type);
      if (converter != null) {
         return converter.convert(s);
      }
      throw new JConvertException(
            type.getName() + " can not be converted, please use other type of attributes in your model!");
   }
}
